/*
 
   isscalarcell.c -- return a boolean array with "isscalar" over a cell array

FORMAT:       iec = isscalarcell(c [, t [, nin]])

Input fields:

      c           N-d cell array
      t           type requirement (matlab name)
      nin         if given and true, false if inf or nan

Output fields:

      isc         boolean array with isscalar(c{i, j, ...})

% Version:  v0.7g
% Build:    9100818
% Date:     Oct-08 2009, 6:37 PM CEST
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

*/

/* matlab includes */
#include "mex.h"
#include "matrix.h"

/* faster isinf/isnan rejection */
#include "isinfnan.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

    const int *dim;
    int ndim = 2, nelem = 0;
    mxClassID cid = 0, tcid = 0;
    char *out, cname[10];
    const mxArray *cell;
    const unsigned char *ninflag;
    bool nin = false;
    const double *dval;
    const float *sval;
    
    VARS_FOR_ISINFNAN
    
    /* argument check */
    if (nrhs < 1 || nlhs > 1)
		mexErrMsgTxt("Bad number of input/output arguments.");
    if (!mxIsCell(*prhs))
		mexErrMsgTxt("First input argument must be of type cell.");
    if ((nrhs > 1) &&
        (mxIsChar(prhs[1])) &&
        (mxGetNumberOfElements(prhs[1]) > 3) &&
        (mxGetNumberOfElements(prhs[1]) < 8)) {
        mxGetString(prhs[1], cname, 8);
        switch (*cname) {
            case 'c':
                cid = mxCHAR_CLASS;
                break;
            case 'd':
                cid = mxDOUBLE_CLASS;
                break;
            case 'i':
                if ((cname[1] == 'n') && (cname[2] == 't'))
                    switch (cname[3]) {
                        case '1':
                            cid = mxINT16_CLASS;
                            break;
                        case '3':
                            cid = mxINT32_CLASS;
                            break;
                        case '6':
                            cid = mxINT64_CLASS;
                            break;
                        case '8':
                            cid = mxINT8_CLASS;
                            break;
                    }
            case 'l':
                cid = mxLOGICAL_CLASS;
                break;
            case 's':
                cid = mxSINGLE_CLASS;
                break;
            case 'u':
                if ((cname[1] == 'i') && (cname[2] == 'n') && (cname[3] == 't'))
                    switch (cname[4]) {
                        case '1':
                            cid = mxUINT16_CLASS;
                            break;
                        case '3':
                            cid = mxUINT32_CLASS;
                            break;
                        case '6':
                            cid = mxUINT64_CLASS;
                            break;
                        case '8':
                            cid = mxUINT8_CLASS;
                            break;
                    }
               break;
        }
    }
    if ((nrhs > 2) &&
        (mxIsLogical(prhs[2])) &&
        (mxGetNumberOfElements(prhs[2]) == 1)) {
            ninflag = (const unsigned char *) mxGetData(prhs[2]);
            if ((ninflag != NULL) &&
                (*ninflag > 0)) {
                nin = true;
                INIT_INF_NAN_BAD_VAL()
            }
    }
    
    /* get dimensions */
    ndim = mxGetNumberOfDimensions(*prhs);
    dim = mxGetDimensions(*prhs);
    nelem = mxGetNumberOfElements(*prhs);
    
    /* create output */
    *plhs = mxCreateNumericArray(ndim, dim, mxLOGICAL_CLASS, mxREAL);
    if (*plhs == NULL)
        mexErrMsgTxt("Couldn't allocate memory for output.");
    if (nelem == 0)
        return;
    out = (char *) mxGetData(*plhs);
    if (out == NULL)
        mexErrMsgTxt("Invalid pointer of output data.");
    
    /* without inf/nan check */
    if (!nin) {
        
        /* without type check */
        if (cid == 0) {
            
            /* iterate over elements */
            for(out = &out[--nelem]; nelem >= 0; --nelem) {
                cell = (const mxArray *) mxGetCell(*prhs, nelem);
                if (cell == NULL)
                    *out-- = 0;
                else
                    *out-- = (mxGetNumberOfElements(cell) == 1) ? 1 : 0;
            }
            
        /* with type check */
        } else {
            
            /* iterate over elements */
            for(out = &out[--nelem]; nelem >= 0; --nelem) {
                cell = (const mxArray *) mxGetCell(*prhs, nelem);
                if (cell == NULL)
                    *out-- = 0;
                else
                    *out-- = ((mxGetNumberOfElements(cell) == 1) &&
                              (mxGetClassID(cell) == cid)) ? 1 : 0;
            }
            
        }
        
    /* with inf/nan check */
    } else {
        
        /* without type check */
        if (cid == 0) {
            
            /* iterate over elements */
            for(out = &out[--nelem]; nelem >= 0; --nelem) {
                cell = (const mxArray *) mxGetCell(*prhs, nelem);
                if (cell == NULL)
                    *out-- = 0;
                else if (mxGetNumberOfElements(cell) != 1)
                    *out-- = 0;
                else {
                    tcid = mxGetClassID(cell);
                    if ((tcid != mxDOUBLE_CLASS) && (tcid != mxSINGLE_CLASS))
                        *out-- = 1;
                    else {
                        if (tcid == mxDOUBLE_CLASS) {
                            dval = (const double *) mxGetData(cell);
                            IF_IS_GOOD_VAL(*dval)
                                *out-- = 1;
                            else
                                *out-- = 0;
                        } else {
                            sval = (const float *) mxGetData(cell);
                            IF_IS_GOOD_VAL(*sval)
                                *out-- = 1;
                            else
                                *out-- = 0;
                        }
                    }
                }
            }
            
        /* with type check */
        } else {
            
            /* iterate over elements */
            for(out = &out[--nelem]; nelem >= 0; --nelem) {
                cell = (const mxArray *) mxGetCell(*prhs, nelem);
                if (cell == NULL)
                    *out-- = 0;
                else if ((mxGetNumberOfElements(cell) != 1) ||
                         (mxGetClassID(cell) != cid))
                    *out-- = 0;
                else if ((cid != mxDOUBLE_CLASS) && (cid != mxSINGLE_CLASS))
                    *out-- = 1;
                else {
                    if (cid == mxDOUBLE_CLASS) {
                        dval = (const double *) mxGetData(cell);
                        IF_IS_GOOD_VAL(*dval)
                            *out-- = 1;
                        else
                            *out-- = 0;
                    } else {
                        sval = (const float *) mxGetData(cell);
                        IF_IS_GOOD_VAL(*sval)
                            *out-- = 1;
                        else
                            *out-- = 0;
                    }
                }
            }
        }
    }
}
